package com.scanner;


import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
 
import android.annotation.SuppressLint;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.os.Environment;
import android.util.Log;
 
public class TakePictureSeries extends Thread{
	
	private static final int FRAMES_TO_IGNORE = 20;
	
	public static String[] mediaDirectoryPath = {""};
	ImageProcessor imgProcessor;
    boolean busy;
    public int[] recievedPoints;
    public static int[] cachedRecievedPoints = null;
    public CameraPreview preview;
    int[] debugCanny;
    int failCount = 0;
    int successCount = 0;
    int eq,mask;
    
    boolean running = true;
    
    static int ignoreCount = FRAMES_TO_IGNORE;
    
    ///events handling
    
    ArrayList<ScannerEventListener> scannerEventObservers = new ArrayList<ScannerEventListener>();
    
    public void StopRunning()
    {
    	running = false;
    }
    
    public void StartRunning()
    {
    	running = true;
    }
    
    public void SetEventObserver(ScannerEventListener observer){
    	scannerEventObservers.add(observer);
    }
    
    public void RaiseScannerEvent(boolean foundPoints, String method)
    {
    	for (ScannerEventListener eventListner: scannerEventObservers)
    	{
    		eventListner.ScannerEventCallback(foundPoints, method);
    	}
    }
    
    ///end event handling
     
    public String getProcMethod()
    {
    	switch(mask)
    	{
    		case 0: 
    			if (eq == 1)
    			{
    				return "equlized no mask";
    			}
    			else
    			{
    				return "not equlized no mask";
    			}
    		case 1:
    			if (eq == 1)
    			{
    				return "equlized inner mask";
    			}
    			else
    			{
    				return "not equlized inner mask";
    			}
    		case 2: 
    			if (eq == 1)
    			{
    				return "equlized outer mask";
    			}
    			else
    			{
    				return "not equlized outer mask";
    			}
    	}
    	return "WRONG! WRONG! WRONG!";
    }
    
    public TakePictureSeries(CameraPreview preview){
        super();
        imgProcessor = new ImageProcessor();
        imgProcessor.StartRunning();
        this.preview = preview;
    }
     
    @Override
    public synchronized void run()
    {
    	Log.d("myLog", "take series running");

        SetPreviewCallback();
        while (running)
        {  
            try{
            	Log.d("myDebug","going to sleep");
            	Thread.sleep(MainScannerActivity.wait4nextAF);            
            	Log.d("myDebug","wake up");  
            }
            catch (InterruptedException e)
            {
            	return;
            }
        }
        return;
    }
          
    private void SetPreviewCallback()
    {
    	Log.d("myDebug","setting preview callback");
        preview.mCamera.setOneShotPreviewCallback(previewCallback);
    }
    
 
    //PreviewCallback to take pictures from the preview
    PreviewCallback previewCallback = new PreviewCallback(){
 
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
          Log.d("myDebug","on preview callback");
	      int width = preview.mCamera.getParameters().getPreviewSize().width ;
	      int height = preview.mCamera.getParameters().getPreviewSize().height;
	      if (data != null)
	      {
	          Log.d("myDebug","on preview callback got data");
	    	  eq = failCount / 30;
	    	  mask = (failCount / 10) % 3;
	    	  recievedPoints = imgProcessor.CalculatePoints(data,height,width,eq,mask);

	          Log.d("myDebug","on preview callback after post processing");
	    	  if (recievedPoints != null && recievedPoints[0] != -1)
	    	  {
	    		successCount += 1; 
	    		ignoreCount = FRAMES_TO_IGNORE;
	    		cachedRecievedPoints = recievedPoints.clone();
	    	  	RaiseScannerEvent(true, getProcMethod());
	    	  	Log.d("myDebug", "preview picture taken");
	    	  }
	    	  else
	    	  {
	    		  successCount -= 1;
	    		  if  (successCount < 100)
	    		  {
	    			  failCount += 1;
	    			  failCount = failCount % 40;
	    		  }
	    		  ignoreCount -= 1;
	    		  if (ignoreCount == 0 || ((failCount % 10) == 0 && successCount < 100))
	    		  {
	    			  RaiseScannerEvent(false, getProcMethod());
	    		  }
	    		  Log.d("myDebug","mamamia");
	    	  }
	      }
	      else
	      {
	    	  Log.d("myDebug", "data is null");
	      }
          if(running)
          {
        	  preview.mCamera.setOneShotPreviewCallback(previewCallback);
          }
          else
          {
        	  Log.d("myDebug", "interrupted");
          }
      }       
    };
        
    @SuppressLint("SimpleDateFormat")
	private static File getOutputPreviewFile()
    {    	
	    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
	              Environment.DIRECTORY_PICTURES), "MyScannerDebugDir");
	    
	 // Create the storage directory if it does not exist
	    if (! mediaStorageDir.exists())
	    {
	        Log.d("myLog", "mediaStorageDir doesn't exist");
	        if (! mediaStorageDir.mkdirs())
	        {
	            Log.d("MyScannerDebugDir", "failed to create directory");
	            return null;
	        }
	    }
	    else
	    {
            Log.d("myLog", "mediaStorageDir exists!!!");
	    }
	    mediaDirectoryPath[0] = mediaStorageDir.getPath();
	 // Create a media file name
	    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
	    File mediaFile;
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "DAN_PREV_IMG_"+ timeStamp + ".bmp");
        Log.d("myLog", "file created");
	
	    return mediaFile;
    }
 
//  http://code.google.com/p/android/issues/detail?id=823&q=onPreviewFrame&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
     static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
            final int frameSize = width * height;
            for (int j = 0, yp = 0; j < height; j++) {
                int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
                for (int i = 0; i < width; i++, yp++) {
                    int y=0;
                    if(yp<yuv420sp.length){
                        y = (0xff & ((int) yuv420sp[yp])) - 16;
                    }
                    if (y < 0) y = 0;
                    if ((i & 1) == 0) {
                        if(uvp<yuv420sp.length){
                            v = (0xff & yuv420sp[uvp++]) - 128;
                            u = (0xff & yuv420sp[uvp++]) - 128;
                        }
                    }
                     
                    int y1192 = 1192 * y;
                    int r = (y1192 + 1634 * v);
                    int g = (y1192 - 833 * v - 400 * u);
                    int b = (y1192 + 2066 * u);
                     
                    if (r < 0) r = 0; else if (r > 262143) r = 262143;
                    if (g < 0) g = 0; else if (g > 262143) g = 262143;
                    if (b < 0) b = 0; else if (b > 262143) b = 262143;
                     
                    rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
                }
            }
        }    
   
}
